home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Oh!X 2001 Spring
/
Oh!X 2001 Spring Special CD-ROM (Japan).7z
/
Oh!X 2001 Spring Special CD-ROM (Japan) (Track 1).bin
/
GALAXY
/
ohx5-1
/
dplaydrive.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
2001-01-10
|
14KB
|
515 lines
/*
Oh!X5号
GalaxyKnightsサンプル1
Copyright(c)2000,Cyberhead,Inc.
DirectPlayドライブモジュール
殆ど無変更です。
*/
#include "stdafx.h"
#include "ohx5_1.h"
#include <dplay.h>
LPDIRECTPLAY4 lpDP;
HANDLE DPhandle; // DirectPlay で受信に用いるイベント・オブジェクトのハンドル
HANDLE ReceiverHandle; // メッセージ受信スレッドのハンドル
DWORD ReceiverID; // メッセージ受信スレッドのスレッドID
bool newdataf = false; // 新規データ、または同期データを送るフラグ
int lost_count = 0; // パケットロストに対応するため、同期データを送るためのカウンタ
char NAMESTR[]="OhX4_GalaxyKnights"; // アプリケーション名
char PLAYERNAME[]="GK_Player"; // プレイヤー名
#define PLAYERS_LOOKS 4 // プレイヤー外見(今回はトーラス,mapctrl.cppの物体リストを参照)
#define MYSELF_LOOKS 0 // 自分から見た自分の姿(今回は「無し」を指定)
DWORD WINAPI Receiver(LPVOID lpParams);
void make_status_container( status_container *cp );
// {B01FFB24-C957-11D3-827A-0000F460DD22}
static const GUID guid_data =
{ 0xB01FFB24, 0xC957, 0x11D3, { 0x82, 0x7A, 0x00, 0x00, 0xF4, 0x60, 0xDD, 0x22 } };
// DirectPlayオブジェクトを作成する
bool init_directplay()
{
HRESULT hr;
CoInitialize(NULL);
hr = CoCreateInstance(
CLSID_DirectPlay,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDirectPlay4A,
(LPVOID *)&lpDP );
if( FAILED(hr) ){ return false; }
DPhandle = CreateEvent(NULL, FALSE, FALSE, NULL);
if (DPhandle == NULL){
lpDP->Release();
return false;
}
ReceiverHandle = CreateThread( NULL, 0, Receiver, NULL, 0, &ReceiverID );
if ( ReceiverHandle == NULL ){
lpDP->Release();
CloseHandle( DPhandle );
return false;
}
return true;
}
// 新しいプレイヤーを登録する
DPPlayer *new_player( DPID player_ID,DWORD name )
{
DPPlayer *dpp;
dpp = new DPPlayer;
dpp->back = NULL;
dpp->next = player_top;
if( player_top!=NULL ) player_top->back = dpp;
player_top = dpp;
if( name != 0 ){ dpp->objp = make_object( name ); } else { dpp->objp = NULL; }
dpp->dplayID = player_ID;
return dpp;
}
// プレイヤーを一人抹消
void kill_player( DPPlayer *dpp )
{
if( dpp==NULL ) return;
if( player_top == dpp ) player_top = player_top->next;
if( dpp->back!=NULL ) dpp->back->next = dpp->next;
if( dpp->next!=NULL ) dpp->next->back = dpp->back;
if( dpp->objp != NULL ) delete_object( dpp->objp );
xDelete( dpp );
}
// DirectPlayオブジェクトの解放
// プレイヤーも全て消去する
void release_directplay()
{
DPPlayer *dpp,*ndp;
xRelease( lpDP );
CoUninitialize();
dpp = player_top;
while( dpp != NULL ){
ndp = dpp->next;
kill_player( dpp );
dpp = ndp;
}
player_top = NULL;
}
// プレイヤーリストからプレイヤーを特定する
DPPlayer *scan_players( DPID player_ID )
{
DPPlayer *dpp = player_top;
while( dpp != NULL ){
if( dpp->dplayID == player_ID ) return dpp;
dpp = dpp->next;
}
return dpp; // 見つからなかった=NULL
}
// キー操作パケットの送信
void send_player_control( DPID id,DWORD key )
{
HRESULT hr;
DPMSG_GENERIC msgpack;
status_container scon;
if( multiplayer == FALSE ) return;
if( newdataf==true ){ // 自分の現在の状態を既に参加しているメンバーに伝える
newdataf = false;
make_status_container( &scon );
hr = lpDP->Send( id, DPID_ALLPLAYERS, 0, &scon, sizeof(status_container) );
} else {
lost_count--;
if( lost_count<=0 ){ // パケットロストに対応するため、120サイクルに1回は、データを丸投げする
lost_count = 120;
newdataf = true;
}
msgpack.dwType = ( key<<16 )| dpmsg_data_packet;
hr = lpDP->Send( id, DPID_ALLPLAYERS, 0, &msgpack, sizeof(DPMSG_GENERIC));
}
}
// 自分自身を生成する(開始直後はシングルプレイヤー)
void make_myself()
{
myself = new_player( 0,0 );
myself->objp = make_object( MYSELF_LOOKS );
multiplayer = false;
}
// サービス・プロバイダーの列挙
BOOL CALLBACK collect_probiders_callback(LPCGUID guid, LPVOID lpcp, DWORD size, LPCDPNAME name, DWORD flag, LPVOID context )
{
HWND hwnd = (HWND)context;
LRESULT lr;
LPVOID lpbuf;
lr = SendDlgItemMessage(
hwnd,
IDC_COMBOSP,
CB_ADDSTRING,
0, (LPARAM)name->lpszShortName );
if ( lr == CB_ERR ){ return TRUE; }
// サービス・プロバイダの情報を格納するメモリを確保する
lpbuf = GlobalAlloc( GPTR, size );
if ( lpbuf == NULL ){ return TRUE; }
// サービス・プロバイダの情報をコピーし,コンボ・ボックスのアイテム・データとして割り当てる
memcpy( lpbuf, lpcp, size );
SendDlgItemMessage(
hwnd,
IDC_COMBOSP,
CB_SETITEMDATA,
(WPARAM)lr,
(LPARAM)lpbuf );
return TRUE;
}
// プロバイダリストの解放
void release_probiderlist(HWND hwnd, int items)
{
int max, i;
LPVOID lp;
max = SendDlgItemMessage(
hwnd,
items,
CB_GETCOUNT,
0, 0 );
for (i = 0; i < max; i++){
lp = (LPVOID)SendDlgItemMessage(
hwnd,
items,
CB_GETITEMDATA,
i, 0);
GlobalFree(lp);
}
SendDlgItemMessage(
hwnd,
items,
CB_RESETCONTENT,
0, 0);
}
// セッションの列挙
BOOL CALLBACK collect_sessions(LPCDPSESSIONDESC2 sessions, LPDWORD timeout, DWORD flag, LPVOID context)
{
HWND hwnd = (HWND)context;
LPGUID guid;
LONG pt;
if ( flag & DPESC_TIMEDOUT) { return FALSE; }
// 列挙で得たセッションリストをリストボックスに溜める
pt = SendDlgItemMessage(
hwnd,
IDC_SESSIONS,
LB_ADDSTRING,
0,
(LPARAM)sessions->lpszSessionName );
if ( pt == CB_ERR ) return TRUE;
// セッションのガイドデータベースを作成、格納
guid = (LPGUID)GlobalAlloc(GPTR, sizeof(GUID));
if ( guid == NULL ) return TRUE;
*guid = sessions->guidInstance;
SendDlgItemMessage(
hwnd,
IDC_SESSIONS,
LB_SETITEMDATA,
(WPARAM)pt,
(LPARAM)guid );
return TRUE;
}
// セッションリスト解放
void release_sessions(HWND hwnd, int item)
{
int max, i;
LPVOID lpt;
max = SendDlgItemMessage(
hwnd,
item,
LB_GETCOUNT,
0, 0);
for( i = 0; i <max; i++ ){
lpt = (LPVOID)SendDlgItemMessage( hwnd, item, LB_GETITEMDATA, i, 0 );
GlobalFree( lpt );
}
SendDlgItemMessage(
hwnd,
item,
LB_RESETCONTENT,
0, 0);
}
// セッション選択ダイアログウインドウ
BOOL CALLBACK session_dialog_proc(HWND handle, UINT Msg, WPARAM wParam, LPARAM lParam)
{
HRESULT hr;
DPSESSIONDESC2 sdesc;
int sno;
int retval = TRUE;
switch( Msg ){
case WM_INITDIALOG: // セッション一覧作成
memset(&sdesc, 0, sizeof(DPSESSIONDESC2));
sdesc.dwSize = sizeof(DPSESSIONDESC2);
sdesc.guidApplication = guid_data;
hr = lpDP->EnumSessions(&sdesc, 0, collect_sessions, handle, DPENUMSESSIONS_AVAILABLE);
if (FAILED(hr)) {
MessageBox(handle, "セッション一覧が作れません", "コネクト失敗", MB_OK | MB_ICONWARNING);
release_sessions(handle, IDC_SESSIONS);
EndDialog(handle, FALSE);
}
return TRUE;
case WM_COMMAND: // セッション参加or新規作成
switch (wParam) {
case IDOK: // OKボタンが押された=選択したセッションを受け取る
sno = SendDlgItemMessage(handle, IDC_SESSIONS, LB_GETCURSEL, 0, 0);
memset(&sdesc, 0, sizeof(DPSESSIONDESC2));
if ( sno != LB_ERR ){ // セッション起動
GUID *guidsession;
sdesc.dwSize = sizeof(DPSESSIONDESC2);
guidsession = (GUID *)SendDlgItemMessage(handle, IDC_SESSIONS, LB_GETITEMDATA, sno , 0);
sdesc.guidInstance = *guidsession;
// 既存のセッションに接続
hr = lpDP->Open(&sdesc, DPOPEN_JOIN);
if ( FAILED(hr) ) retval = FALSE;
} else { // OKボタンを押したとき、セッション未選択=新しいセッションを作る
sdesc.dwSize = sizeof(DPSESSIONDESC2);
sdesc.dwFlags = DPSESSION_MIGRATEHOST | DPSESSION_KEEPALIVE;
sdesc.guidApplication = guid_data;
sdesc.dwMaxPlayers = MAXPLAYERS;
sdesc.lpszSessionNameA = NAMESTR;
// セッションの新規作成
hr = lpDP->Open(&sdesc, DPOPEN_CREATE);
if( FAILED(hr) ) retval = FALSE;
}
release_sessions( handle, IDC_SESSIONS );
EndDialog( handle, retval );
return TRUE;
case IDCANCEL:
release_sessions(handle, IDC_SESSIONS );
EndDialog(handle, FALSE);
return TRUE;
default:
return FALSE;
}
default:
return FALSE;
}
return TRUE;
}
// サービスプロバイダーリスト選択用ダイアログウインドウ
BOOL CALLBACK probiderlist_dialog_proc(HWND handle, UINT Msg, WPARAM wParam, LPARAM lParam)
{
HRESULT hr;
int iSelectedProvider;
LPVOID lpConnection;
switch( Msg ){
case WM_INITDIALOG: // サービスプロバイダーリスト作成
release_probiderlist(handle, IDC_COMBOSP);
lpDP->EnumConnections(NULL, collect_probiders_callback, handle, 0);
return TRUE;
case WM_COMMAND:
switch (wParam) {
case IDOK:
// [OK]ボタンが押されたときの処理
iSelectedProvider = SendDlgItemMessage(handle, IDC_COMBOSP, CB_GETCURSEL, 0, 0);
if (iSelectedProvider != CB_ERR) {
// サービス・プロバイダを初期化する
lpConnection = (LPVOID)SendDlgItemMessage(handle, IDC_COMBOSP, CB_GETITEMDATA, iSelectedProvider, 0);
hr = lpDP->InitializeConnection(lpConnection, 0);
release_probiderlist(handle, IDC_COMBOSP);
if ( SUCCEEDED(hr) || (hr == DPERR_ALREADYINITIALIZED) ){
EndDialog(handle, TRUE);
} else {
MessageBox(handle, "サービスプロバイダーの初期化に失敗しました", NAMESTR, MB_OK | MB_ICONWARNING);
EndDialog(handle, FALSE);
}
} else {
MessageBox(handle, "サービスプロバイダーを設定してください", NAMESTR, MB_OK | MB_ICONWARNING);
}
return TRUE;
case IDCANCEL:
release_probiderlist(handle, IDC_COMBOSP);
EndDialog(handle, FALSE);
return TRUE;
default:
return FALSE;
}
break;
default:
return FALSE;
}
return TRUE;
}
// 対戦モードにする
void connect_player( HWND hwnd )
{
HRESULT hr;
DPID dID;
// セッション開始
// マルチプレイヤーモードにする
multiplayer = true;
if (DialogBox(hInst, MAKEINTRESOURCE(IDD_CONNECT), hwnd, (DLGPROC)probiderlist_dialog_proc)){
// セッション選択のダイアログ・ボックスを表示する
if (DialogBox(hInst, MAKEINTRESOURCE(IDD_SESSION), hwnd, (DLGPROC)session_dialog_proc)){
// プレーヤーを作成する
DPNAME dpName;
// プレーヤーの名前を設定
memset(&dpName, 0, sizeof(DPNAME));
dpName.dwSize = sizeof(DPNAME);
dpName.lpszShortNameA = PLAYERNAME;
dpName.lpszLongNameA = NULL;
// プレーヤーの作成
hr = lpDP->CreatePlayer( &dID, &dpName, DPhandle, NULL, 0, 0);
// 作成したプレーヤーのDPIDを保存
myself->dplayID = dID;
newdataf = true;
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
}
}
}
// 回線切断する
// 自分以外のプレイヤーを消去
// セッションを終了
// シングルプレイヤーモードにする
void disconnect_player( HWND hwnd )
{
DPPlayer *dpp,*ndp;
multiplayer = false;
if (myself->dplayID != NULL) { // プレーヤーの削除
lpDP->DestroyPlayer( myself->dplayID );
myself->dplayID = NULL;
dpp = player_top;
while( dpp != NULL ){
ndp = dpp->next;
if( dpp != myself ) kill_player( dpp );
dpp = ndp;
}
InvalidateRect(hwnd, NULL, TRUE);
UpdateWindow(hwnd);
}
lpDP->Close();
}
// 既存プレイヤーを生成する
void preset_player( DPPlayer *dpp,status_container *cp )
{
dpp->objp->pos = cp->position;
dpp->objp->rotate = cp->rotation;
dpp->objp->rudder = cp->rudder;
dpp->objp->move = cp->speed;
dpp->objp->type = cp->name;
}
// 自分の情報をデータコンテナに詰め込む
void make_status_container( status_container *cp )
{
cp->dwType = dpmsg_now_status;
cp->name = PLAYERS_LOOKS;
cp->position = myself->objp->pos;
cp->rotation = myself->objp->rotate;
cp->rudder = myself->objp->rudder;
cp->speed = myself->objp->move;
}
// メッセージ送受信のスレッドを用意
DWORD WINAPI Receiver(LPVOID lpParams)
{
// メッセージを受信するスレッド
DPID fromID,toID;
LPDPMSG_GENERIC msgbuf;
DWORD msgbufsize;
HRESULT stat,hr;
HWND hwnd;
DPPlayer *dpp;
status_container scon;
hwnd = (HWND)lpParams;
while (WaitForSingleObject(DPhandle, INFINITE) == WAIT_OBJECT_0) {
//メッセージの取り出し
msgbuf = NULL;
msgbufsize = 0;
stat = DP_OK;
while( SUCCEEDED( stat ) ){
stat = lpDP->Receive(
&fromID,
&toID,
DPRECEIVE_ALL,
NULL,
&msgbufsize ); // 受信バッファ作成
if( stat != DPERR_BUFFERTOOSMALL ) break;
if( msgbuf != NULL ) GlobalFree( msgbuf );
if( ( msgbuf = (LPDPMSG_GENERIC)GlobalAlloc( GPTR, msgbufsize ) )==NULL ){
stat = DPERR_OUTOFMEMORY;
break;
}
// データを受信
stat = lpDP->Receive(
&fromID,
&toID,
DPRECEIVE_ALL,
msgbuf,
&msgbufsize );
if( FAILED(stat) ) break;
// 受信したメッセージの処理
switch( fromID ){
case DPID_SYSMSG: // システム・メッセージ
switch ( msgbuf->dwType ) {
case DPSYS_CREATEPLAYERORGROUP://ユーザーが作られた
// 新規参加者のために自分の状態を告げる
make_status_container( &scon );
hr = lpDP->Send(myself->dplayID,DPID_ALLPLAYERS, 0, &scon, sizeof(status_container));
break;
case DPSYS_DESTROYPLAYERORGROUP://ユーザーが減った
dpp = scan_players( ((LPDPMSG_DESTROYPLAYERORGROUP)msgbuf)->dpId );
kill_player( dpp );
break;
}
break;
default: // 各々のプレイヤーの挙動データ処理
dpp = scan_players( fromID );
if( dpp == NULL ){ // 相手は新規
dpp = new_player( fromID, PLAYERS_LOOKS );
dpp->objp->type = 0; // 外見無しにしておく
}
if( msgbuf->dwType == dpmsg_now_status ){
preset_player( dpp,(status_container *)msgbuf );
} else {
command_player( dpp->objp, *( (DWORD *)msgbuf ) );
}
}
}
if( msgbuf != NULL ) GlobalFree( msgbuf );
}
ExitThread(0);
return 0;
}